#ifndef CPPPRIMER5THCHAPTER17
#define CPPPRIMER5THCHAPTER17
#include <cstdlib>
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>
#include <tuple>
#include <memory>
#include <new>
#include <map>
#include <set>
#include <bitset>
#include <cmath>

using std::cerr;
using std::cin;
using std::cout;
using std::endl;
using std::ifstream;
using std::string;
using std::vector;

// #define NDEBUG
#include "../../hello_log.h"

#include "../chapter7/chapter7.h"

template <typename T>
int rangeForContainer(const T &a)
{
    for (auto b : a)
    {
        cout << b << ",";
    }
    cout << endl;
    return 0;
}

typedef std::tuple<std::string, int, std::shared_ptr<std::vector<std::string>>, std::shared_ptr<std::set<int>>> QueryResultTuple;

class TextQueryUseTuple
{
public:
    TextQueryUseTuple(std::ifstream &in_file);
    QueryResultTuple query(const std::string &word) const;

private:
    // contents: index is line number, string is line content.
    std::shared_ptr<std::vector<std::string>> contents;
    // words_map: string is word, and set<int> is a set of line number in which word appears at least once.
    std::shared_ptr<std::map<std::string, std::set<int>>> words_map;
    // word_count: string is word, and int is the frequency of word.
    std::shared_ptr<std::map<std::string, int>> word_count;
};

// Exercises Section 17.1.1
// Exercise 17.1: Define a tuple that holds three int values and initialize the
// members to 10, 20, and 30.
int exercise17_1();

// Exercise 17.2: Define a tuple that holds a string, a vector<string>,
// and a pair<string, int>.
int exercise17_2();

// Exercise 17.3: Rewrite the TextQuery programs from § 12.3 (p. 484) to
// use a tuple instead of the QueryResult class.
// Explain which design you think is better and why.
// Answer: I prefer not use tuple, as it's easy to access or modify QueryResult rather than tuple.
int exercise17_3();

typedef std::tuple<vector<Sales_data>::size_type,
                   vector<Sales_data>::const_iterator,
                   vector<Sales_data>::const_iterator>
    matches;

// Exercises Section 17.1.2
// Exercise 17.4: Write and test your own version of the findBook function.
int exercise17_4(int argc, char **argv);

typedef std::pair<vector<Sales_data>::size_type,
                  std::pair<vector<Sales_data>::const_iterator,
                            vector<Sales_data>::const_iterator>>
    pair_matches;

// Exercise 17.5: Rewrite findBook to return a pair that holds an index and
// a pair of iterators.
int exercise17_5(int argc, char **argv);

class obj_matches
{
public:
    obj_matches(vector<Sales_data>::size_type index,
                vector<Sales_data>::const_iterator const_begin,
                vector<Sales_data>::const_iterator const_end) : idx(index), cbegin(const_begin), cend(const_end){};

    vector<Sales_data>::size_type idx;
    vector<Sales_data>::const_iterator cbegin;
    vector<Sales_data>::const_iterator cend;
};

// Exercise 17.6: Rewrite findBook so that it does not use tuple or pair.
int exercise17_6(int argc, char **argv);

// Exercise 17.7: Explain which version of findBook you prefer and why.
// Answer: tuple is more flexible than pair and normal object.
int exercise17_7();

// Exercise 17.8: What would happen if we passed Sales_data() as the
// third parameter to accumulate in the last code example in this section?
// Answer: in Sales_data's operator+ defination, only when obj's isbn are same, the rest part are accumulated.
int exercise17_8();

// Exercises Section 17.2.1
// Exercise 17.9: Explain the bit pattern each of the following bitset objects
// contains:
// (a) bitset<64> bitvec(32);
// (b) bitset<32> bv(1010101);
// (c) string bstr; cin >> bstr; bitset<8>bv(bstr);
int exercise17_9();

// Exercises Section 17.2.2
// Exercise 17.10: Using the sequence 1, 2, 3, 5, 8, 13, 21, initialize a
// bitset that has a 1 bit in each position corresponding to a number in this
// sequence. Default initialize another bitset and write a small program to
// turn on each of the appropriate bits.
int exercise17_10();

template <unsigned int T>
class answers
{
public:
    std::bitset<T> ansSet;
    void setAns(unsigned int num, bool answer)
    {
        if (num < T)
        {
            if (answer)
            {
                ansSet.set(num);
            }
        }
        else
        {
            throw std::runtime_error("out of answers's range.");
        }
    }

    void setAll(unsigned int num)
    {
        if (num < std::pow(T, 2))
        {
            ansSet = std::bitset<T>(num);
        }
        else
        {
            throw std::runtime_error("out of answers's range.");
        }
    }
};

// Exercise 17.11: Define a data structure that contains an integral object to
// track responses to a true/false quiz containing 10 questions. What changes, if
// any, would you need to make in your data structure if the quiz had 100
// questions?
int exercise17_11();

// Exercise 17.12: Using the data structure from the previous question, write a
// function that takes a question number and a value to indicate a true/false
// answer and updates the quiz results accordingly.
int exercise17_12();

// Exercise 17.13: Write an integral object that contains the correct answers
// for the true/false quiz. Use it to generate grades on the quiz for the data
// structure from the previous two exercises.
int exercise17_13();

//  20240802 didn't read 17.3 to 17.5
int exercise17_14();
int exercise17_15();
int exercise17_16();
int exercise17_17();
int exercise17_18();
int exercise17_19();
int exercise17_20();
int exercise17_21();
int exercise17_22();
int exercise17_23();
int exercise17_24();
int exercise17_25();
int exercise17_26();
int exercise17_27();
int exercise17_28();
int exercise17_29();
int exercise17_30();
int exercise17_31();
int exercise17_32();
int exercise17_33();
int exercise17_34();
int exercise17_35();
int exercise17_36();
int exercise17_37();
int exercise17_38();
int exercise17_39();

#endif